package pl.us.ij.plugins.segmentation;

import ij.IJ;
import ij.ImagePlus;
import ij.gui.GUI;
import ij.plugin.frame.PlugInFrame;
import ij.process.ImageProcessor;
import pl.us.ij.plugins.segmentation.commands.ResetCommand;
import pl.us.ij.plugins.segmentation.commands.SharpenCommand;
import pl.us.ij.plugins.segmentation.commands.WatershedCommand;
import pl.us.ij.plugins.segmentation.commands.cvt.CvtSegmentationCommand;
import pl.us.ij.plugins.segmentation.commands.cvt.CvtShowEdgesCommand;
import pl.us.ij.plugins.segmentation.commands.edges.*;
import pl.us.ij.plugins.segmentation.commands.filters.AveragedFilterCommand;
import pl.us.ij.plugins.segmentation.commands.filters.GaussFilterCommand;
import pl.us.ij.plugins.segmentation.commands.filters.MedianFilterCommand;
import pl.us.ij.plugins.segmentation.commands.fire.FireSegmentationCommand;
import pl.us.ij.plugins.segmentation.commands.threshold.*;
import pl.us.ij.plugins.segmentation.commands.watershed.CombineSegmentationCommand;
import pl.us.ij.plugins.segmentation.commands.watershed.OCCOCommand;
import pl.us.ij.plugins.segmentation.commands.watershed.WatershedSegmentationCommand;
import pl.us.ij.plugins.segmentation.forms.ControlTemplateForm;
import pl.us.ij.plugins.segmentation.infrastructure.CommandParams;
import pl.us.ij.plugins.segmentation.infrastructure.CommandRunner;
import pl.us.ij.plugins.segmentation.infrastructure.ICommand;
import pl.us.ij.plugins.segmentation.infrastructure.ICommandInvokeHandler;
import pl.us.ij.plugins.segmentation.localization.Localization;

import java.awt.event.WindowEvent;
import java.util.HashMap;


public class SegmentationPlugin
        extends PlugInFrame
        implements ICommandInvokeHandler  {

    private HashMap<String, ICommand> commands;
    private int previousId = 0;

    private static SegmentationPlugin _instance;

    public SegmentationPlugin() {
        super(Localization.getString("segmentation.name"));

        if (_instance == null) {
            _instance = this;
        } else {
            _instance.toFront();
            return;
        }
        addListeners();
        initComponents();
        initCommands();
        registerCommands();
    }

    @Override
    public void processWindowEvent(WindowEvent e) {
        super.processWindowEvent(e);
        if (e.getID() == WindowEvent.WINDOW_CLOSING) {
            _instance = null;
        }
    }

    public void invoke(String commandName) {
        this.invoke(commandName, null);
    }

    public void invoke(String commandName, CommandParams params) {
        IJ.log(commandName);

        ImagePlus image = IJ.getImage();
        
        if (image == null) {
            IJ.beep();
            IJ.showStatus(Localization.getString("segmentation.warning.noImage"));
            return;
        }

        if (!image.lock()) {
            previousId = 0;
            return;
        }

        ImageProcessor imageProcessor = image.getProcessor();
        int imageId = image.getID();

        if (previousId != imageId) {
            imageProcessor.snapshot();
        }
        previousId = imageId;

        if (commandName == null || commandName.isEmpty()) {
            IJ.beep();
            IJ.showMessage(Localization.getString("message.error"), Localization.getString("segmentation.unknownCommand"));
            image.unlock();
            return;
        }

        ICommand command = lookupCommandBy(commandName);

        if (command == null) {
            IJ.beep();
            IJ.showMessage(Localization.getString("message.error"), Localization.getString("segmentation.notRegistredCommand"));
            image.unlock();
            return;
        }

        command.setImage(image);
        command.setImageProcessor(imageProcessor);
        command.setParams(params);

        new CommandRunner(command);
    }

    private void addListeners() {
//        ImagePlus.addImageListener(this);
    }

    private void initComponents() {
        addKeyListener(IJ.getInstance());

        add(ControlTemplateForm.getMainPanel(this));
        this.setSize(790, 500);
//        pack();
        GUI.center(this);
        setVisible(true);
    }

    private void initCommands() {
        this.commands = new HashMap<String, ICommand>();
    }

    private void registerCommands() {
        registerCommand(new ResetCommand());
        registerCommand(new SharpenCommand());
        registerCommand(new WatershedCommand());
        registerCommand(new GaussFilterCommand());
        registerCommand(new AveragedFilterCommand());
        registerCommand(new MedianFilterCommand());
        registerCommand(new TwoLevelThresholdCommand());
        registerCommand(new OneLevelThresholdCommand());
        registerCommand(new IterativeHistogramThresholdCommand());
        registerCommand(new HistogramThresholdCommand());
        registerCommand(new GradientThresholdCommand());
        registerCommand(new DetectEdgesCommand());
        registerCommand(new ErosionCommand());
        registerCommand(new DilatationCommand());
        registerCommand(new SkeletonCommand());
        registerCommand(new BranchCuttingCommand());
        registerCommand(new OCCOCommand());
        registerCommand(new WatershedSegmentationCommand());
        registerCommand(new CombineSegmentationCommand());
        registerCommand(new CvtSegmentationCommand());
        registerCommand(new CvtShowEdgesCommand());
        registerCommand(new FireSegmentationCommand());
    }

    private void registerCommand(ICommand command) {
        IJ.log(command.getName());

        this.commands.put(command.getName(), command);
    }

    private ICommand lookupCommandBy(String label) {
        return commands.get(label);
    }


}








